package protocol.generic;

import java.util.ArrayList;

import protocol.domain.InstantMessage;
import protocol.domain.Status;

/**
 * Abstract class representing the Instant Message protocol used in our client.
 * The run method of this class will handle connect and login in its own thread.
 * 
 * @author hAmmeRoL
 * 
 */
public abstract class AbstractProtocolManager implements Runnable {

	// indicating whether debug information will be printed
	public boolean DEBUG_ENABLED = true;

	protected String protocol;

	// user name of the account of this protocol
	protected String userID;

	// user password of the account of this protocol
	protected String password;

	// server host name of the protocol server. e.g. talk.google.com
	protected String hostName;

	// port number of the protocol server. e.g. 5222
	protected int port;

	protected ProtocolEventHandler eventHandler;

	public void setEventHandler(ProtocolEventHandler handler) {
		this.eventHandler = handler;
	}

	public ProtocolEventHandler getEventHandler() {
		return eventHandler;
	}

	/**
	 * Connect to the remote server
	 * 
	 * @precondition. none
	 * @postcondition. the connection is established
	 * @modifies. none
	 * 
	 * @throws ProtocolException
	 *             indicating network failure
	 */
	public abstract void connect() throws ProtocolException;

	/**
	 * Login to the protocol server. The login will send an available presence
	 * change to all your clients
	 * 
	 * @precondition. The connection must be established
	 * @postcondition. The user is authenticated
	 * @modifies. none
	 * 
	 * @throws ProtocolException
	 *             Exception indicating failure of connection or login
	 */
	public abstract void login() throws ProtocolException;

	/**
	 * Close the connection to the remote server
	 * 
	 * @precondition. none
	 * @postcondition. The connection to the remote server is lost
	 * @modifies. none
	 * 
	 */
	public abstract void close();

	/**
	 * Send a message using an InstantMessage instance
	 * 
	 * @precondition. the user is logged in and the destination id of the
	 *                message is valid
	 * @postcondition. a message is sent to the client
	 * @modifies. none
	 * 
	 * @param message
	 *            the InstantMessage instance containing the user id,
	 *            destination id and text message
	 * @throws ProtocolException
	 *             Exception indicating failure of sending message
	 */
	public abstract void sendMessage(InstantMessage message)
			throws ProtocolException;

	/**
	 * Get the avatar of the client if available
	 * 
	 * @precondition. the user is logged in and the clientID is valid
	 * @postcondition. get the avatar of the client if available
	 * @modifies. none
	 * 
	 * @param clientID
	 * @return the avatar of the client
	 * @throws ProtocolException
	 *             indicating failure of getting the avatar
	 */
	public abstract byte[] getAvatar(String clientID) throws ProtocolException;

	/**
	 * Set the new avatar of the user
	 * 
	 * @precondition. the user is logged in
	 * @postcondition. the avatar is changed to the new given avatar
	 * @modifies. the avatar of the user
	 * 
	 * @param fileName
	 *            the new avatar picture file to be set
	 */
	public abstract void setAvatar(String fileName) throws ProtocolException;

	/**
	 * Create a new group. If no new entry is added into this new group, then it
	 * may not appear the next time user is logged on
	 * 
	 * @precondition. user is logged in
	 * @postcondition. a new group is created
	 * @modifies. group list
	 * 
	 * @param groupName
	 *            the group name to be created
	 */
	public abstract void createGroup(String groupName);

	/**
	 * Rename a group
	 * 
	 * @precondition. oldName is a valid group name. newName does not conflict
	 *                with another name in the list
	 * @postcondition. group name changed
	 * @modifies. the group name
	 * 
	 * @param oldName
	 *            the name of the group to be changed
	 * @param newName
	 *            the new name
	 */
	public abstract void renameGroup(String oldName, String newName);

	/**
	 * Delete a group and all its entries from the list
	 * 
	 * @precondition. groupName is valid
	 * @postcondition. the group and all its entries are deleted.
	 * @modifies. the buddy list
	 * 
	 * @param groupName
	 *            the group name to be deleted
	 * @throws ProtocolException
	 *             if error occurs
	 */
	public abstract void deleteGroup(String groupName) throws ProtocolException;

	/**
	 * Move a entry to another group
	 * 
	 * @precondition. oldGroupName, clientID and newGroupName are valid
	 * @postcondition. entry changed to another group
	 * @modifies. buddy list layout
	 * 
	 * @param oldGroupName
	 *            group name where entry to be removed
	 * @param clientID
	 *            the id associated with this entry
	 * @param newGroupName
	 *            group name where entry to be added
	 * @throws ProtocolException
	 *             if error occurs
	 */
	public abstract void moveEntryToGroup(String oldGroupName, String clientID,
			String newGroupName) throws ProtocolException;

	/**
	 * Copy a entry to another group
	 * 
	 * @precondition. clientID, newGroupName are valid
	 * @postcondition. entry copied to another group
	 * @modifies. group layout
	 * 
	 * @param clientID
	 *            the id associated with this entry
	 * @param newGroupName
	 *            the group name to be copied to
	 * @throws ProtocolException
	 *             if error occurs
	 */
	public abstract void copyEntryToGroup(String clientID, String newGroupName)
			throws ProtocolException;

	/**
	 * Delete a entry in the group and if no other group is associated with this
	 * entry, it will be added to the unfiled group
	 * 
	 * @precondition. groupName and clientID are valid
	 * @postcondition. entry deleted
	 * @modifies. group list
	 * 
	 * @param groupName
	 *            the group name of the entry
	 * @param clientID
	 *            id of the entry
	 * @throws ProtocolException
	 *             if error occurs
	 */
	public abstract void deleteEntryFromGroup(String groupName, String clientID)
			throws ProtocolException;

	/**
	 * Delete the entry from the roster and will not appear in all the groups
	 * and cancel all subscriptions
	 * 
	 * @precondition. clientID is valid
	 * @postcondition. entry deleted from all groups
	 * @modifies. buddy list
	 * 
	 * @throws ProtocolException
	 *             indicating something went wrong
	 */
	public abstract void deleteEntry(String clientID) throws ProtocolException;

	/**
	 * Add a entry to and subscribe to that client
	 * 
	 * @precondition. clientID is valid, groups are valid
	 * @postcondition. entry is added to the buddy list
	 * @modifies. buddy list
	 * 
	 * @param clientID the cliendID to add
	 * @param alias alias of that client
	 * @param groups groups to be added to
	 * @throws ProtocolException indicating error
	 */
	public abstract void addEntry(String clientID, String alias, String[] groups)
			throws ProtocolException;

	public abstract void sendSubscriptionRequest(String clientID);
	
	public abstract void sendAuthenticatedReply(String clientID);
	
	public abstract void sendDeniedReply(String clientID);
	
	public abstract void block(String clientID);
	
	public abstract boolean isBlocked(String clientID);
	
	public abstract void cancelBlock(String clientID);
	
	public abstract void setPresence(Status status);

	/**
	 * Get a group list containing all the groups in this manager
	 * 
	 * @precondition. the user is logged in
	 * @postcondition. get all the groups of this protocol manager
	 * @modifies. none
	 * 
	 * @return The ArrayList containing all the groups in this manager
	 */
	public abstract ArrayList<Group> getGroups();

	/**
	 * Get the user id
	 * 
	 * @precondition. none
	 * @postcondition. none
	 * @modifies. none
	 * 
	 * @return the user id
	 */
	public String getUserID() {
		return userID;
	}

	public String getProtocol() {
		return protocol;
	}
}
